package cn.edu.xmu.oomall.customer.service;

import cn.edu.xmu.oomall.core.util.Common;
import cn.edu.xmu.oomall.core.util.JacksonUtil;
import cn.edu.xmu.oomall.core.util.ReturnNo;
import cn.edu.xmu.oomall.core.util.ReturnObject;
import cn.edu.xmu.oomall.customer.dao.CouponDao;
import cn.edu.xmu.oomall.customer.microservice.CouponActivityService;
import cn.edu.xmu.oomall.customer.microservice.vo.CouponActivityVoInfo;
import cn.edu.xmu.oomall.customer.model.bo.Coupon;
import cn.edu.xmu.oomall.customer.model.po.CouponPoExample;
import cn.edu.xmu.oomall.customer.model.vo.CouponAllRetVo;
import cn.edu.xmu.oomall.customer.model.vo.CouponRetVo;
import cn.edu.xmu.oomall.customer.model.vo.SimpleActivityRetVo;
import cn.edu.xmu.oomall.customer.model.vo.SimpleCustomerRetVo;
import cn.edu.xmu.privilegegateway.annotation.util.InternalReturnObject;
import cn.edu.xmu.privilegegateway.annotation.util.bloom.BloomFilter;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;


import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static cn.edu.xmu.privilegegateway.annotation.util.Common.cloneVo;
import static cn.edu.xmu.privilegegateway.annotation.util.Common.genSeqNum;
import static cn.edu.xmu.privilegegateway.annotation.util.Common.setPoCreatedFields;

/**
 * @author Jianxiang Xie
 * @date 2021-12-9 20:12:57
 *
 * @modifiedBy Jiazhe Yuan
 * @date 2021-12-20 00:30:01
 * @modify setNewCouponInfo方法的genSeqNum
 *
 * @modifiedBy Jiazhe Yuan
 * @time 2021-12-23 11:31:36
 * @info 对接oomall-additional
 */

@Service
public class CouponService implements InitializingBean {

    @Autowired
    CouponDao couponDao;

    @Autowired
    CouponActivityService couponActivityService;

    @Autowired(required = false)
    BloomFilter<String> bloomFilter;

    private final String COUPONFILTER = "couponFilter";
    private final String COUPONFILTERKEY = "actid_%d_customerId_%d";

    @Value("${customer.bloomfilter.coupon.error-rate}")
    private double couponError = 0.01;
    @Value("${customer.bloomfilter.coupon.capacity}")
    private int couponCapacity = 10000;

    @Override
    public void afterPropertiesSet() throws Exception {

        if (!bloomFilter.checkFilter(COUPONFILTER)) {
            bloomFilter.newFilter(COUPONFILTER, couponError, couponCapacity);
        }
    }

    /**
     * 用于测试时重置redisbloom
     */
    public void delFilter() {
        bloomFilter.deleteFilter(COUPONFILTER);
    }

    /**
     * 用户获取自己的优惠券列表 分页
     *
     * @param loginUserId 用户id
     * @param state       优惠券状态
     * @param page        页
     * @param pageSize    页大小
     * @return 优惠券分页
     */
    public ReturnObject getCoupons(Long loginUserId, Integer state, Integer page, Integer pageSize) {
        //通过用户id与优惠券状态获取优惠券
        CouponPoExample example = new CouponPoExample();
        CouponPoExample.Criteria criteria = example.createCriteria();
        criteria.andCustomerIdEqualTo(loginUserId);
        if (state != null) {
            criteria.andStateEqualTo(state.byteValue());
        }
        var ret = couponDao.getCouponsByExample(example, page, pageSize);
        if (!ret.getCode().equals(ReturnNo.OK)) {
            return ret;
        }
        List<Coupon> coupons = ((PageInfo<Coupon>) ret.getData()).getList();
        List<CouponRetVo> couponRetVos = new ArrayList<>();
        //将BO对象转换为Vo对象
        for (Coupon coupon : coupons) {
            try {
                InternalReturnObject<CouponActivityVoInfo> internalRet = couponActivityService.getCouponActivityById(coupon.getActivityId());
                if (!internalRet.getErrno().equals(ReturnNo.OK.getCode())) {
                    return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR, internalRet.getErrmsg());
                }
                //openFeign返回的是LinkedHashMap，用fastJson转化为对象
                CouponActivityVoInfo retAct = (CouponActivityVoInfo) internalRet.getData();
                //SimpleActivityRetVo svo = cloneVo(retAct, SimpleActivityRetVo.class);
                CouponRetVo couponRetVo = cloneVo(coupon, CouponRetVo.class);
                //couponRetVo.setActivity(svo);
                couponRetVo.setActivityId(retAct.getId());
                couponRetVos.add(couponRetVo);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        PageInfo pageInfo = PageInfo.of(coupons);
        pageInfo.setList(couponRetVos);
        return Common.getPageRetVo(new ReturnObject(pageInfo), CouponRetVo.class);
    }

    /**
     * 用户领取优惠券
     *
     * @param actId         活动id
     * @param loginUserId   用户id
     * @param loginUserName 用户名
     * @return 结果
     */
    public ReturnObject gainCoupon(Long actId, Long loginUserId, String loginUserName) {
        //判断是否已经领取过优惠券 返回633
        //TODO:不可重复领优惠卷 应该返回633错误码,returnNo中的错误码待修改
        if (bloomFilter.checkValue(COUPONFILTER, String.format(COUPONFILTERKEY, actId, loginUserId))) {
            return new ReturnObject(ReturnNo.STATENOTALLOW, "已经领取过本活动的优惠券");
        }
        //获取对应的活动
        InternalReturnObject<CouponActivityVoInfo> internalRet = null;
        try {
            internalRet = couponActivityService.getCouponActivityById(actId);
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        System.out.println(JacksonUtil.toJson(internalRet));

        if (!internalRet.getErrno().equals(ReturnNo.OK.getCode())) {
            return new ReturnObject(ReturnNo.INTERNAL_SERVER_ERR, internalRet.getErrmsg());
        }
        System.out.println(JacksonUtil.toJson(internalRet.getData()));

        CouponActivityVoInfo retAct = new CouponActivityVoInfo();
        //表示该优惠活动不需要优惠卷，返回504错误
        try {
            retAct = (CouponActivityVoInfo) internalRet.getData();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
        System.out.println("=============== here 1 —————————————————————— ");

        try {
            if (retAct.getQuantity() == -1) {
                return new ReturnObject(ReturnNo.RESOURCE_ID_NOTEXIST, ReturnNo.RESOURCE_ID_NOTEXIST.getMessage());
            }
            //现在还未到开始领券时间 返回630
            if (LocalDateTime.now().isBefore(retAct.getCouponTime().toLocalDateTime())) {
                return new ReturnObject(ReturnNo.COUPON_NOTBEGIN, ReturnNo.COUPON_NOTBEGIN.getMessage());
            }
            //优惠活动终止 返回632
            if (LocalDateTime.now().isAfter(retAct.getEndTime().toLocalDateTime())) {
                return new ReturnObject(ReturnNo.COUPON_END, ReturnNo.COUPON_END.getMessage());
            }
            //活动不为上线状态
            if (retAct.getState() != 1) {
                return new ReturnObject(ReturnNo.STATENOTALLOW, "活动已经下线");
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        System.out.println("————————————here 2 ————————————————————");

        int quantityType = retAct.getQuantityType();
        Coupon coupon = new Coupon();
        List<CouponAllRetVo> retVoList = new ArrayList<>();

        //每人数量
        try {
            if (quantityType == 0) {
                if (bloomFilter.checkValue(COUPONFILTER, String.format(COUPONFILTERKEY, actId, loginUserId))) {
                    return new ReturnObject(ReturnNo.STATENOTALLOW, "已经领取过本活动的优惠券");
                }
                bloomFilter.addValue(COUPONFILTER, String.format(COUPONFILTERKEY, actId, loginUserId));
                //生成n张优惠券，加入到数据库表中
                //将优惠券一次性发放完
                for (int i = 0; i < retAct.getQuantity(); i++) {
                    //设置优惠券的相关信息，插入数据库
                    coupon = setNewCouponInfo(coupon, retAct, loginUserId, loginUserName);
                    ReturnObject returnObject = couponDao.insertCoupon(coupon);
                    if (!returnObject.getCode().equals(ReturnNo.OK)) {
                        return new ReturnObject(returnObject.getCode(), "领取优惠券失败");
                    }
                    retVoList.add(getCouponAllRetVo(coupon, retAct));
                }
                //将此用户的信息加入布隆过滤器中
            } else if (quantityType == 1) {
                if (bloomFilter.checkValue(COUPONFILTER, String.format(COUPONFILTERKEY, actId, loginUserId))) {
                    return new ReturnObject(ReturnNo.STATENOTALLOW, "已经领取过本活动的优惠券");
                }
                //将此用户的信息加入布隆过滤器中
                bloomFilter.addValue(COUPONFILTER, String.format(COUPONFILTERKEY, actId, loginUserId));
                //总数控制
                //减少优惠券总数
                var daoRet1 = couponDao.decreaseCouponQuantity(actId, retAct.getNumKey(), 1, retAct.getQuantity());
                //将优惠券信息加入数据库
                coupon = setNewCouponInfo(coupon, retAct, loginUserId, loginUserName);
                ReturnObject daoRet2 = couponDao.insertCoupon(coupon);
                //插入成功且扣库存成功
                if (daoRet1.getCode().equals(ReturnNo.OK) && daoRet2.getCode().equals(ReturnNo.OK)) {
                    retVoList.add(getCouponAllRetVo(coupon, retAct));
                } else {
                    return daoRet1;
                }
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        System.out.println("=============== here 3 —————————————————————— ");

        return new ReturnObject(retVoList);
    }

    /**
     * 为新优惠券设置属性
     *
     * @param coupon        待设置的Coupon对象
     * @param retAct        活动对象
     * @param loginUserId   用户id
     * @param loginUserName 用户名
     * @return 修改后的Coupon对象
     */
    private Coupon setNewCouponInfo(Coupon coupon, CouponActivityVoInfo retAct, Long loginUserId, String loginUserName) {
        coupon.setId(0L);
        // TODO 这个platform到底是干什么的
        coupon.setCouponSn(genSeqNum(1));
        if (retAct.getValidTerm() == 0) {
            coupon.setBeginTime(retAct.getBeginTime().toLocalDateTime());
            coupon.setEndTime(retAct.getEndTime().toLocalDateTime());
        } else {
            //优惠券的有效时间为当前时间加上ValidTerm
            //具体为活动结束时间 和 现在时间加上天数 的较小者
            coupon.setBeginTime(LocalDateTime.now());
            coupon.setEndTime(
                    LocalDateTime.now().plusDays(retAct.getValidTerm()).isAfter(retAct.getEndTime().toLocalDateTime()) ?
                            retAct.getEndTime().toLocalDateTime() : LocalDateTime.now().plusDays(retAct.getValidTerm())
            );
        }
        coupon.setCustomerId(loginUserId);
        coupon.setActivityId(retAct.getId());
        coupon.setName(retAct.getName() + "优惠券");
        coupon.setState(Coupon.State.RECEIVED.getCode().byteValue());
        setPoCreatedFields(coupon, loginUserId, loginUserName);
        return coupon;
    }

    /**
     * 利用Coupon对象得到CouponAllRetVo对象
     *
     * @param coupon Coupon对象
     * @param act    活动对象
     * @return CouponAllRetVo
     */
    private CouponAllRetVo getCouponAllRetVo(Coupon coupon, CouponActivityVoInfo act) {
        CouponAllRetVo couponAllRetVo = cloneVo(coupon, CouponAllRetVo.class);
        SimpleActivityRetVo simpleActivityRetVo = cloneVo(act, SimpleActivityRetVo.class);
        SimpleCustomerRetVo creator = new SimpleCustomerRetVo(coupon.getCustomerId(), coupon.getCreatorName());
        SimpleCustomerRetVo modifier = new SimpleCustomerRetVo(coupon.getModifierId(), coupon.getModifierName());
        couponAllRetVo.setActivity(simpleActivityRetVo);
        couponAllRetVo.setCreator(creator);
        couponAllRetVo.setModifier(modifier);
        return couponAllRetVo;
    }

    public ReturnObject getCouponStates() {
        List<Map<String, Object>> stateList = new ArrayList<>();
        for (Coupon.State state : Coupon.State.values()) {
            Map<String, Object> tmp = new HashMap<>(16);
            tmp.put("code", state.getCode());
            tmp.put("name", state.getDescription());
            stateList.add(tmp);
        }
        return new ReturnObject(stateList);
    }
}